package com.start.common.tools;

import cn.hutool.core.util.ClassLoaderUtil;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

@UtilityClass
public class ClassTools {
    /**
     * 获取类的所有属性，包括父类
     *
     * @param object
     * @return
     */
    public List<Field> getAllFields(Object object) {
        Class<?> clazz = object.getClass();
        return getAllFields(clazz);
    }

    /**
     * 获取类的所有属性，包括父类
     * 如果子类包含父类相同的属性名称 以子类为准
     *
     * @param clazz
     * @return
     */
    public List<Field> getAllFields(Class<?> clazz) {
        Map<String, Field> fieldList = new HashMap<>();
        while (clazz != null) {
            Map<String, Field> fieldMap = Arrays.stream(clazz.getDeclaredFields()).filter(e -> !fieldList.containsKey(e.getName())).collect(Collectors.toMap(Field::getName, e -> e));
            fieldList.putAll(fieldMap);
            clazz = clazz.getSuperclass();
        }
        return new ArrayList<>(fieldList.values());
    }

    public List<Field> getEffectiveFields(Object object) {
        return getEffectiveFields(object.getClass());
    }

    public List<Field> getEffectiveFields(Class<?> clazz) {
        List<Field> allFields = getAllFields(clazz);
        return allFields.stream().filter(field -> !Modifier.isFinal(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())).collect(Collectors.toList());
    }


    /**
     * 获取指定名称成员变量 （不包含 常量，静态变量）
     *
     * @param fieldName
     * @param o
     * @return
     */
    public List<Field> getTargetField(String fieldName, Object o) {
        List<Field> allFields = getAllFields(o);
        return allFields.stream().filter(field -> field.getName().equals(fieldName) && !Modifier.isFinal(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())).collect(Collectors.toList());
    }

    /**
     * 根据类全路径查找类型对象
     *
     * @param clazzName
     * @return
     */
    public static Class loadClass(String clazzName) {
        return ClassLoaderUtil.loadClass(clazzName);
    }

    /**
     * 是否存在类型
     *
     * @param clazzName
     * @return
     */
    public static boolean hasClass(String clazzName) {
        if (StringUtils.isAllBlank(clazzName)) {
            return false;
        }
        try {
            Class.forName(clazzName);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 根据类全路径查找类对象 并判读该类是否是某一个类的子类
     *
     * @param clazzName   类路径
     * @param parentClazz 父类对象
     * @param <T>
     * @return
     */
    public static <T> Class loadClass(String clazzName, Class<T> parentClazz) {
        Class clazzByClazzName = loadClass(clazzName);
        if (!parentClazz.isAssignableFrom(clazzByClazzName)) {
            return null;
        }
        return clazzByClazzName;
    }

    public static Object createObject(String className) {
        try {
            Class<?> clazz = Class.forName(className);
            return createObject(clazz);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T createObject(Class<T> clazz) {
        try {
            return clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }
}
